--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
tests/backend/test_lifecycle.py ec74a2651e897325b14269ae52d11b1e12f0b6e2 (ec74a265) Text, 6.62 KB
T8b949e# SPDX-License-Identifier: 0BSD
Tff7b72import T7ee787gc
Tff7b72import T7ee787os
Tff7b72import T7ee787shutil
Tff7b72import T7ee787sqlite3
Tff7b72import T7ee787tempfile
Tff7b72from T7ee787unittestT7ee787.T7ee787mock Tff7b72import Te6edf3MagicMockTb4b4b4, Te6edf3patch
Tff7b72import T7ee787pytest
Tff7b72import T7ee787RNS
Tff7b72from T7ee787hypothesis Tff7b72import Te6edf3givenTb4b4b4, Te6edf3settings
Tff7b72from T7ee787hypothesis Tff7b72import Te6edf3strategies Tff7b72as Te6edf3st
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787provider Tff7b72import Te6edf3DatabaseProvider
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787identity_context Tff7b72import Te6edf3IdentityContext
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787web_audio_bridge Tff7b72import Te6edf3WebAudioBridge
Tff7b72def Td2a8fftest_database_provider_disposalTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Test that DatabaseProvider correctly closes connections."""
Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3tempfileTff7b72.Td2a8ffgettempdirTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6fftest_disposal.dbTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3db_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3db_pathTb4b4b4)
T8b949e# Ensure any existing singleton is cleared
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72= Tff7b72None
Tff7b72tryTb4b4b4:
Te6edf3provider Tff7b72= Te6edf3DatabaseProviderTff7b72.Td2a8ffget_instanceTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3conn Tff7b72= Te6edf3providerTff7b72.Td2a8ffconnection
Tff7b72assert Tffa657isinstanceTb4b4b4(Te6edf3connTb4b4b4, Te6edf3sqlite3Tff7b72.Td2a8ffConnectionTb4b4b4)
T8b949e# Test close()
Te6edf3providerTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Te6edf3sqlite3Tff7b72.Td2a8ffProgrammingErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffclosed databaseTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3connTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffSELECT 1Ta5d6ff"Tb4b4b4)
T8b949e# Re-open
Te6edf3conn2 Tff7b72= Te6edf3providerTff7b72.Td2a8ffconnection
Tff7b72assert Te6edf3conn2 Tff7b72is Tff7b72not Te6edf3conn
T8b949e# Test close_all()
Te6edf3providerTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Te6edf3sqlite3Tff7b72.Td2a8ffProgrammingErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffclosed databaseTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3conn2Tff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"Ta5d6ffSELECT 1Ta5d6ff"Tb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3db_pathTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3db_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72= Tff7b72None
Tff7b72def Td2a8fftest_web_audio_bridge_disposalTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Test that WebAudioBridge correctly manages clients and cleanup."""
Te6edf3mock_tele_mgr Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_tele_mgrTff7b72.Td2a8ffis_voicemail_session_active Tff7b72= Tff7b72False
Te6edf3mock_config_mgr Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3bridge Tff7b72= Te6edf3WebAudioBridgeTb4b4b4(Te6edf3mock_tele_mgrTb4b4b4, Te6edf3mock_config_mgrTb4b4b4)
Te6edf3mock_client Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_tele Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_teleTff7b72.Td2a8ffactive_call Tff7b72= Tff7b72True
Te6edf3mock_tele_mgrTff7b72.Td2a8fftelephone Tff7b72= Te6edf3mock_tele
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.web_audio_bridge.WebAudioSourceTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.web_audio_bridge.WebAudioSinkTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.web_audio_bridge.TeeTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.web_audio_bridge.PipelineTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3bridgeTff7b72.Td2a8ffattach_clientTb4b4b4(Te6edf3mock_clientTb4b4b4)
Tff7b72assert Te6edf3mock_client Tff7b72in Te6edf3bridgeTff7b72.Td2a8ffclients
Te6edf3bridgeTff7b72.Td2a8ffon_call_endedTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3bridgeTff7b72.Td2a8fftx_source Tff7b72is Tff7b72None
Tff7b72assert Te6edf3bridgeTff7b72.Td2a8ffrx_sink Tff7b72is Tff7b72None
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3bridgeTff7b72.Td2a8ffclientsTb4b4b4) Tff7b72== T79c0ff0
Tff7b72def Td2a8fftest_identity_context_teardown_completenessTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Verify that teardown cleans up all major components."""
Te6edf3mock_identity Tff7b72= Te6edf3MagicMockTb4b4b4(Te6edf3specTff7b72=Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4)
Te6edf3mock_identityTff7b72.Td2a8ffhash Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6fftest_hash_32_bytes_long_01234567Ta5d6ff"
Te6edf3mock_identityTff7b72.Td2a8ffget_private_keyTff7b72.Td2a8ffreturn_value Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ffmock_pkTa5d6ff"
Te6edf3mock_app Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_appTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.DatabaseTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.ConfigManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.create_lxmf_routerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.IntegrityManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(
Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.AutoPropagationManagerTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3context Tff7b72= Te6edf3IdentityContextTb4b4b4(Te6edf3mock_identityTb4b4b4, Te6edf3mock_appTb4b4b4)
Te6edf3contextTff7b72.Td2a8ffstart_background_threads Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffregister_announce_handlers Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffsetupTb4b4b4(Tb4b4b4)
T8b949e# Capture instances
Te6edf3db_instance Tff7b72= Te6edf3contextTff7b72.Td2a8ffdatabase
Te6edf3auto_prop_instance Tff7b72= Te6edf3contextTff7b72.Td2a8ffauto_propagation_manager
Te6edf3contextTff7b72.Td2a8ffteardownTb4b4b4(Tb4b4b4)
T8b949e# Verify component cleanup
Te6edf3db_instanceTff7b72.Td2a8ff_checkpoint_and_closeTff7b72.Td2a8ffassert_calledTb4b4b4(Tb4b4b4)
Te6edf3auto_prop_instanceTff7b72.Td2a8ffstopTff7b72.Td2a8ffassert_calledTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3contextTff7b72.Td2a8ffrunning Tff7b72is Tff7b72False
Tff7b72def Td2a8fftest_identity_context_memory_leakTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Verify that IdentityContext can be garbage collected after teardown."""
Te6edf3mock_identity Tff7b72= Te6edf3MagicMockTb4b4b4(Te6edf3specTff7b72=Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4)
Te6edf3mock_identityTff7b72.Td2a8ffhash Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ffleak_test_hash_32_bytes_long_012Ta5d6ff"
Te6edf3mock_identityTff7b72.Td2a8ffget_private_keyTff7b72.Td2a8ffreturn_value Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ffmock_pkTa5d6ff"
Te6edf3mock_app Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_appTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
Tff7b72import T7ee787weakref
T8b949e# We use a list to store the ref so we can access it after the function scope
Te6edf3leak_ref Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffrun_lifecycleTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.DatabaseTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.ConfigManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.create_lxmf_routerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.IntegrityManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffRNS.TransportTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3context Tff7b72= Te6edf3IdentityContextTb4b4b4(Te6edf3mock_identityTb4b4b4, Te6edf3mock_appTb4b4b4)
Te6edf3contextTff7b72.Td2a8ffstart_background_threads Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffregister_announce_handlers Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffsetupTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffteardownTb4b4b4(Tb4b4b4)
Te6edf3leak_refTff7b72.Td2a8ffappendTb4b4b4(Te6edf3weakrefTff7b72.Td2a8ffrefTb4b4b4(Te6edf3contextTb4b4b4)Tb4b4b4)
T8b949e# End of with block and function scope should clear 'context'
Te6edf3run_lifecycleTb4b4b4(Tb4b4b4)
T8b949e# Break any potential cycles in the app mock which might have captured the context
Te6edf3mock_appTff7b72.Td2a8ffreset_mockTb4b4b4(Tb4b4b4)
T8b949e# Multiple collection rounds
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4:
Te6edf3gcTff7b72.Td2a8ffcollectTb4b4b4(Tb4b4b4)
T8b949e# Check if it was collected
Tff7b72assert Te6edf3leak_refTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4(Tb4b4b4) Tff7b72is Tff7b72NoneTb4b4b4, Ta5d6ff"Ta5d6ffIdentityContext was not garbage collectedTa5d6ff"
Tf0883e@settingsTb4b4b4(Te6edf3deadlineTff7b72=Tff7b72NoneTb4b4b4)
Tf0883e@givenTb4b4b4(Te6edf3stTff7b72.Td2a8ffintegersTb4b4b4(Te6edf3min_valueTff7b72=T79c0ff1Tb4b4b4, Te6edf3max_valueTff7b72=T79c0ff3Tb4b4b4)Tb4b4b4)
Tff7b72def Td2a8fftest_identity_context_repeated_lifecycleTb4b4b4(Te6edf3nTb4b4b4)Tb4b4b4:
T8b949e"""Fuzz the lifecycle by repeating setup/teardown multiple times with new instances."""
Te6edf3mock_identity Tff7b72= Te6edf3MagicMockTb4b4b4(Te6edf3specTff7b72=Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4)
Te6edf3mock_identityTff7b72.Td2a8ffhash Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6fffuzz_hash_32_bytes_long_01234567Ta5d6ff"
Te6edf3mock_identityTff7b72.Td2a8ffget_private_keyTff7b72.Td2a8ffreturn_value Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ffmock_pkTa5d6ff"
Te6edf3mock_app Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3mock_appTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
Tff7b72with Tb4b4b4(
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.DatabaseTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.ConfigManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.create_lxmf_routerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffmeshchatx.src.backend.identity_context.IntegrityManagerTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3patchTb4b4b4(Ta5d6ff"Ta5d6ffRNS.TransportTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(Te6edf3nTb4b4b4)Tb4b4b4:
Te6edf3context Tff7b72= Te6edf3IdentityContextTb4b4b4(Te6edf3mock_identityTb4b4b4, Te6edf3mock_appTb4b4b4)
Te6edf3contextTff7b72.Td2a8ffstart_background_threads Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffregister_announce_handlers Tff7b72= Te6edf3MagicMockTb4b4b4(Tb4b4b4)
Te6edf3contextTff7b72.Td2a8ffsetupTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3contextTff7b72.Td2a8ffrunning Tff7b72is Tff7b72True
Te6edf3contextTff7b72.Td2a8ffteardownTb4b4b4(Tb4b4b4)
Tff7b72assert Te6edf3contextTff7b72.Td2a8ffrunning Tff7b72is Tff7b72False
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3mock_appTff7b72.Td2a8ffstorage_dirTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Te6edf3mock_appTff7b72.Td2a8ffstorage_dirTb4b4b4)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────